
#include <BStream>
#include "member_BSonDocument.h"

using namespace BWE;

member_BSonDocument::member_BSonDocument(BSonDocument* sondocument)
{
	boss = sondocument;
	last = 0;
}
member_BSonDocument::~member_BSonDocument()
{

}

const SonFormat* member_BSonDocument::nodeFormat(const BSonNode* node)
{
	member_BSonNode* sonmem = son_member(node);
	if (!sonmem->format.text.empty())
		return &sonmem->format;
	return &format;
}
void member_BSonDocument::makeFormat(BSonNode* node)
{
	if (node)
	{
		member_BSonNode* mem = son_member(node);
		mem->format.toString();

		BArray<BSonNodeHolder>& children = mem->children;
		for (int i = 0; i < children.size(); i++)
		{
			BSonNode* child = children[i];
			makeFormat(child);
		}
	}
}
bool member_BSonDocument::removeTextIndent(BString& text, int level)
{
	if (text.size())
	{
		BString indents('\n');
		indents.append('\t', level);
		int pos = text.find(indents);
		while (pos < text.size())
		{
			text.remove(pos + 1, level);
			pos = text.find(indents, pos);
		}
	}
	return true;
}

bool member_BSonDocument::readNode(BSonNode* node, const BString& sontext, int &pos, int level)
{
	BString text;
	BString value;
	char linebreak = 0;
	while (pos < sontext.size())
	{
		char code = sontext[pos++];
		if (code == '\n')
			linebreak = '\n';
		if (code == '=')
		{
			value.reset();
			while (pos < sontext.size())
			{
				code = sontext[pos++];
				if (code == ';')
					break;
				if (code == '}')
				{
					pos--;
					break;
				}
				value.append(code);
			}
			text.trimmed();
			if (text.empty())
			{
				log << "name is empty : " << "=" << value;
				return false;
			}
			value.trimmed();
			node->setAttrib(text, value);
			text.reset();
			continue;
		}
		if (code == '{')
		{
			text.trimmed();
			BSonNode* child = new BSonNode(text);
			readNode(child, sontext, pos, level + 1);
			node->addChild(child);
			text.reset();
			continue;
		}
		if (code == ';')
		{
			text.trimmed();
			removeTextIndent(text, level + 1);
			son_member(node)->text = text;
			text.reset();
			continue;
		}
		if (code == '}')
		{
			text.trimmed();
			if (text.size())
			{
				removeTextIndent(text, level + 1);
				son_member(node)->text = text;
			}
			return true;
		}
		text.append(code);
	}
	return false;
}
void member_BSonDocument::writeNode(const BSonNode* node, BString& sontext, int level)
{
	member_BSonNode* sonmem = son_member(node);
	const SonFormat* fmt = nodeFormat(node);

	if (last == '\n')
		sontext.append('\t', level);
	sontext << node->name() << fmt->head_prev;
	last = fmt->head_prev;

	if (last == '\n')
		sontext.append('\t', level);
	sontext << '{' << fmt->head_post;
	last = fmt->head_post;

	for (auto it = sonmem->attribMap.begin(); it.valid(); ++it)
	{
		if (last == '\n')
			sontext.append('\t', level + 1);
		sontext << it.key() << fmt->equal_prev << '=' << fmt->equal_post << it.value() << ';' << fmt->end_post;
		last = fmt->end_post;
	}

	if (sonmem->text.size())
	{
		if (last == '\n')
		{
			sontext.append('\t', level + 1);
			writeIndentText(sonmem->text, sontext, level);
		}
		else
		{
			sontext << sonmem->text;
		}
		sontext << ';' << fmt->end_post;
		last = fmt->end_post;
	}

	if (sonmem->children.size())
	{
		for (int i = 0; i < node->childCount(); i++)
		{
			const BSonNode* child = node->child(i);
			writeNode(child, sontext, level + 1);
		}
	}

	if (fmt->tail_prev && fmt->tail_prev != last)
	{
		sontext << fmt->tail_prev;
		last = fmt->tail_prev;
	}
	if (last == '\n')
		sontext.append('\t', level);
	sontext << '}' << fmt->tail_post;
	last = fmt->tail_post;
}
void member_BSonDocument::writeIndentText(const BString& text, BString& sontext, int level)
{
	int pos = 0;
	while (pos < text.size())
	{
		int end = text.find('\n', pos);
		if (end < text.size())
		{
			sontext.append(text.cstr(), pos, end + 1);
			sontext.append('\t', level + 1);
		}
		pos = end + 1;
	}
}

bool member_BSonDocument::readNode(BSonNode* node, const BStream& stream, int level)
{
	BString text;
	BString value;
	char linebreak = 0;
	char code = 0;
	while (stream.read(code))
	{
		if (code == '\n')
			linebreak = '\n';
		if (code == '=')
		{
			value.reset();
			while (stream.read(code))
			{
				if (code == ';')
					break;
				if (code == '}')
				{
					stream.seek(-1);
					break;
				}
				value.append(code);
			}
			text.trimmed();
			if (text.empty())
			{
				log << "name is empty : " << "=" << value;
				return false;
			}
			value.trimmed();
			node->setAttrib(text, value);
			text.reset();
			continue;
		}
		if (code == '{')
		{
			text.trimmed();
			BSonNode* child = new BSonNode(text);
			readNode(child, stream, level + 1);
			node->addChild(child);
			text.reset();
			continue;
		}
		if (code == ';')
		{
			text.trimmed();
			removeTextIndent(text, level + 1);
			son_member(node)->text.append(text);
			son_member(node)->text.append(';');
			text.reset();
			continue;
		}
		if (code == '}')
		{
			text.trimmed();
			if (text.size())
			{
				removeTextIndent(text, level + 1);
				son_member(node)->text.append(text);
			}
			return true;
		}
		text.append(code);
	}
	return false;
}
void member_BSonDocument::writeNode(const BSonNode* node, BStream& stream, int level)
{
	member_BSonNode* sonmem = son_member(node);
	const SonFormat* fmt = nodeFormat(node);

	if(last == '\n')
		stream.write('\t', level);
	stream << node->name() << fmt->head_prev;
	last = fmt->head_prev;

	if (last == '\n')
		stream.write('\t', level);
	stream << '{' << fmt->head_post;
	last = fmt->head_post;

	for (auto it = sonmem->attribMap.begin(); it.valid(); ++it)
	{
		if(last == '\n')
			stream.write('\t', level + 1);
		stream << it.key() << fmt->equal_prev << '=' << fmt->equal_post << it.value() << ';' << fmt->end_post;
		last = fmt->end_post;
	}

	if (sonmem->text.size())
	{
		if (last == '\n')
		{
			stream.write('\t', level + 1);
			writeIndentText(sonmem->text, stream, level);
		}
		else
		{
			stream << sonmem->text;
		}
		stream << ';' << fmt->end_post;
		last = fmt->end_post;
	}

	if (sonmem->children.size())
	{
		for (int i = 0; i < node->childCount(); i++)
		{
			const BSonNode* child = node->child(i);
			writeNode(child, stream, level + 1);
		}
	}

	if (fmt->tail_prev && fmt->tail_prev != last)
	{
		stream << fmt->tail_prev;
		last = fmt->tail_prev;
	}
	if (last == '\n')
	{
		stream.write('\t', level);
	}
	stream << '}' << fmt->tail_post;
	last = fmt->tail_post;
}
void member_BSonDocument::writeIndentText(const BString& text, BStream& stream, int level)
{
	int pos = 0;
	while (pos < text.size())
	{
		int end = text.find('\n', pos);
		if (end == text.size())
		{
			stream.write(text.cstr() + pos, end - pos);
			break;
		}
		stream.write(text.cstr() + pos, end - pos + 1);
		stream.write('\t', level + 1);
		pos = end + 1;
	}
}

